#include "Calculator.hpp"
#include "TcpServer.hpp"
#define ROOT "/"
#define DEVNULL "/dev/null"
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>

MyCal cal;

string Handler(string& src_str){
    string tmp;
    string ret;
    while(Decode(src_str,&tmp)){
        //到了函数里面那么tmp一条完整的报文,
        Request req;
        req.Deserialization(tmp);
        Response rsp = cal.Cal(req);
        string s;
        rsp.Serialization(&s);
        //添加报头
        Encode(s);
        ret += s; 
    }
    return ret;
}



void Daemon(bool ischdir, bool isclose)
{
    //守护进程需要忽略几个必要信号
    signal(SIGCHLD,SIG_IGN); //子进程退出信号
    signal(SIGPIPE,SIG_IGN); //管道读端退出，写端继续写
    //1. 不能为进程组的领导者，不能作为第一个进程
    if (fork() > 0) exit(0);
    //下面的操作就是子进程
    setsid(); //创建 ssession id
    //改变子进程的工作目录为根目录， 换位根目录之后可以更方便的访问系统资源 (绝对路径) 
    //当然也可以不改变，所以我们传入第一个参数ischdir
    if (ischdir) 
    {
        chdir(ROOT);
    }
    //关闭标准输入输出文件
    //但是我们不能直接关闭，由于代码中可能有往标准输出输出的步骤，如果直接关闭的话就会报错
    //所以我们传入第二个参数 isclose ,让用户自己来控制是否关闭
    if (isclose)
    {
        close(0);
        close(1);
        close(2);
    }
    else {
        int fd = open(DEVNULL,O_WRONLY);
        dup2(fd,0);
        dup2(fd,1);
        dup2(fd,2);
        close(fd); //把不需要的关闭即可，只有当一个文件的计数器--为0，才会彻底释放文件
    }

}

int main(int argc,char* argv[]){
    if (argc != 2){
        Useage(argv[0]);
        exit(1);
    }
    ENABLEFILESTRATEGY();
    Daemon(false,false);
    //下面的就是守护进程了
    uint16_t serverport = stoi(argv[1]);
    udp_server us(serverport);
    us.Insert(Handler);
    us.Init();
    us.Start();
    return 0;
}